package com.mediatek.camera.panorama;

import com.android.camera.R;
import com.android.camera.CameraHolder;
import com.mediatek.camera.ui.ProgressIndicator;
import com.android.camera.ui.Rotatable;

import com.mediatek.xlog.Xlog;
import android.hardware.Camera;
import android.hardware.Camera.Size;


import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.animation.AlphaAnimation;
import android.view.animation.Transformation;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;

public class PanoramaController implements Camera.AUTORAMAMVCallback
	,Camera.AUTORAMACallback {
	private static final String TAG = "PanoramaController";

	//ICS==>
	private View mPanoView;		
	private ImageView mDirectionSigns[] = new ImageView[4];//up,down,left,right
	private ImageView mCenterWindow;	
	private View mNaviWindow;
	private ProgressIndicator mProgressIndicator;
	private Drawable mNormalWindowDrawable;
	private Drawable mCollimatedWindowDrawable;		
    private Camera mCameraDevice;
	private Handler mHandler;
	private Size mPreviewSize;
	//<==ICS
	
	private static final int DIRECTION_RIGHT  = 0;
	private static final int DIRECTION_LEFT = 1;
	private static final int DIRECTION_UP  = 2;
	private static final int DIRECTION_DOWN = 3;
	private static final int DIRECTION_UNKNOWN = 4;
	
	private int mDirection = DIRECTION_UNKNOWN;
	private int mState;
	private int mDisplayOrientaion;

    private static final int IDLE = 0;
    private static final int STARTED = 1;
    private static final int MERGING = 2;

    private static final int TARGET_DISTANCE_HORIZONTAL = 160;
    private static final int TARGET_DISTANCE_VERTICAL = 120;
    

    private static final int NUM_AUTORAMA_CAPTURE = 9;
    private int mCurrentNum = 0;
    
    private boolean mStopping;
    private boolean mShowingCollimatedDrawable;
		
	public PanoramaController(Activity activity,CaptureEventListener l) {
		initializeViews(activity);
		mProgressIndicator = new ProgressIndicator(activity,ProgressIndicator.TYPE_PANO);
		mCaptureEventListener = l;

        mHandler = new Handler(Looper.getMainLooper());
	}

	public void setCamera(Camera camera) {
		mCameraDevice = camera;
		mPreviewSize = mCameraDevice.getParameters().getPreviewSize();
	}
	
	public void setDisplayOrientation(int displayOrientation) {
        mDisplayOrientaion = displayOrientation;
	}
	
	private void initializeViews(Activity activity) {
		mPanoView = activity.findViewById(R.id.pano_view);		

		mDirectionSigns[DIRECTION_RIGHT] = (ImageView)activity.findViewById(R.id.pano_right);
		mDirectionSigns[DIRECTION_LEFT] = (ImageView)activity.findViewById(R.id.pano_left);
		mDirectionSigns[DIRECTION_UP] = (ImageView)activity.findViewById(R.id.pano_up);
		mDirectionSigns[DIRECTION_DOWN] = (ImageView)activity.findViewById(R.id.pano_down);

		mCenterWindow = (ImageView)activity.findViewById(R.id.center_window);
		mNaviWindow = activity.findViewById(R.id.navi_window);

		android.content.res.Resources res = activity.getResources();
		mNormalWindowDrawable = res.getDrawable(R.drawable.ic_pano_normal_window); 
		mCollimatedWindowDrawable = res.getDrawable(R.drawable.ic_pano_collimated_window); 
    }

	public boolean hasCaptured() {
		Xlog.e(TAG, "hasCaptured mCurrentNum: " + mCurrentNum);
		return mState != IDLE && mCurrentNum > 0;
	}

	private void resetDirectionIcons() {
		for (int i = 0; i < 4; i++) {
			mDirectionSigns[i].setSelected(false);
			mDirectionSigns[i].setVisibility(View.VISIBLE); 		
		}	
	}
		
	private void updateDirection(int direction) {
		Xlog.e(TAG, "updateDirection mDirection: " + mDirection+" direction: " + direction);
		if (mDirection != direction) {
			mDirection = direction;
			if (mDirection != DIRECTION_UNKNOWN) {
				for (int i = 0; i < 4; i++) {
					if (i == mDirection) {						
						mDirectionSigns[i].setSelected(true);
						mDirectionSigns[i].setVisibility(View.VISIBLE);			
					} else {
						mDirectionSigns[i].setVisibility(View.INVISIBLE);			
					}
				}
			}
		}
	}					

	private View.OnClickListener OkOnClickListener = new View.OnClickListener() {
		public void onClick(View v) {
			mProgressIndicator.enableOkCancelButton(false);
			if (mCaptureEventListener != null) {
				mCaptureEventListener.onKeyPressed(true);
			}
		}
	};

	private View.OnClickListener CancelOnClickListener = new View.OnClickListener() {
		public void onClick(View v) {
			mProgressIndicator.enableOkCancelButton(false);
			if (mCaptureEventListener != null) {
				mCaptureEventListener.onKeyPressed(false);
			}			
		}
	};	


	private CaptureEventListener mCaptureEventListener;
	
    public interface CaptureEventListener {
        void onCaptureDone(boolean isMerge);
        void onMergeStarted();
		void onKeyPressed(boolean okKey);
    }		

	public boolean start() {
		if (mCameraDevice != null && mState == IDLE && !mStopping) {
			mState = STARTED;
			mCurrentNum = 0;
			mShowingCollimatedDrawable = false;
			mDirection = DIRECTION_UNKNOWN;

			doStart();
			
			resetDirectionIcons();
			mPanoView.setVisibility(View.VISIBLE);	
			mProgressIndicator.setVisibility(View.VISIBLE);				
			mProgressIndicator.enableOkCancelButton(true);
			mProgressIndicator.setOkCancelClickListener(OkOnClickListener,CancelOnClickListener);
			return true;
		} else {
			Xlog.e(TAG, "start mState: " + mState);
			return false;			
		}
	}

	private void stopAsync(final boolean isMerge) {
		Xlog.d(TAG, "stopAsync mStopping: " + mStopping);
		
		if (mStopping) return;
		
		mStopping = true;
        Thread stopThread = new Thread(new Runnable() {
        	public void run() {
            	doStop(isMerge);
				mHandler.post(new Runnable() {
					 public void run() {
						 mStopping = false;
						 if (!isMerge) {//if isMerge is true, onHardwareStopped will be called in onCapture.
						 	onHardwareStopped(false);
						 }
					 }
				});	 				
            }
        });
        stopThread.start();	
	}

	private void doStart() {
		Xlog.d(TAG, "doStart");		
		mCameraDevice.setAUTORAMACallback(this);
		mCameraDevice.setAUTORAMAMVCallback(this);
		mCameraDevice.startAUTORAMA(NUM_AUTORAMA_CAPTURE);
	}

	private void doStop(boolean isMerge) {
		Xlog.d(TAG, "doStop isMerge "+isMerge);
		
		if (mCameraDevice != null) {
			CameraHolder holder = CameraHolder.instance();
			synchronized(holder) {
				if (holder.isSameCameraDevice(mCameraDevice)) {//means that hw was shutdown and no need to call stop anymore.
					mCameraDevice.stopAUTORAMA(isMerge ? 1 : 0);	
				} else {
					Xlog.w(TAG, "doStop device is release? ");
				}
			}
		}
    }

	private void onHardwareStopped(boolean isMerge) {
		Xlog.d(TAG, "onHardwareStopped isMerge: " + isMerge);
		
		if (isMerge) {
			mCameraDevice.setAUTORAMACallback(null);
			mCameraDevice.setAUTORAMAMVCallback(null);
		}	
		
		if (mCaptureEventListener != null) {
			mCaptureEventListener.onCaptureDone(isMerge);
		}			   
		
		mProgressIndicator.enableOkCancelButton(false);
		mProgressIndicator.setProgress(0);//reset to 0
		mPanoView.setVisibility(View.INVISIBLE);	
		mNaviWindow.setVisibility(View.INVISIBLE);  
	}

	public void stop(boolean isMerge) {
		Xlog.d(TAG, "stop mState: " + mState);
		
		if (mCameraDevice != null && mState == STARTED) {
			mState = isMerge ? MERGING : IDLE;
			if (!isMerge) {
				mCameraDevice.setAUTORAMACallback(null);
				mCameraDevice.setAUTORAMAMVCallback(null);
			} else {
			   if (mCaptureEventListener != null) {
			       mCaptureEventListener.onMergeStarted();
			   }	
			}			
			stopAsync(isMerge);
		} 
	}	

		
        public void onCapture() {
            Xlog.i(TAG, "onCapture: " + mCurrentNum + ",mState: "+mState);
			if (mState == IDLE) return;

			if (mCurrentNum == NUM_AUTORAMA_CAPTURE || mState == MERGING) {
                Xlog.i(TAG, "autorama done");
		        mState = IDLE;
				onHardwareStopped(true);
            } else if (mCurrentNum >= 0 && mCurrentNum < NUM_AUTORAMA_CAPTURE) {
			   mProgressIndicator.setProgress(mCurrentNum+1);
			   mNaviWindow.setVisibility(View.INVISIBLE);
			   
			   mCenterWindow.setImageDrawable(mCollimatedWindowDrawable);
			   if (mShowingCollimatedDrawable) {
					mHandler.removeCallbacksAndMessages(null);
			   }			   
			   mShowingCollimatedDrawable = true;
	           mHandler.postDelayed(new Runnable() {
	           		public void run() {
	                	mShowingCollimatedDrawable = false;
						mCenterWindow.setImageDrawable(mNormalWindowDrawable);
	                }
	           }, 500);			   
	        } else {
                Xlog.w(TAG, "onCapture is called in abnormal state");
			}
			
			mCurrentNum++;
			if (mCurrentNum == NUM_AUTORAMA_CAPTURE) {
				stop(true);
			}
        }
    
        public void onFrame(int xy, int direction) {
			
			//Xlog.i(TAG, "onFrame mShowingCollimatedDrawable = "+mShowingCollimatedDrawable);
        	if (direction == DIRECTION_UNKNOWN || mShowingCollimatedDrawable || 
					mState != STARTED || mCurrentNum < 1) {
				return;
        	}
			//Xlog.i(TAG, "onFrame xy = "+xy + " direction = "+direction);

            short x = (short)((xy & 0xFFFF0000) >> 16);
            short y = (short)(xy & 0x0000FFFF);
			int cwx = mCenterWindow.getLeft()+mCenterWindow.getPaddingLeft();
			int cwy = mCenterWindow.getTop()+mCenterWindow.getPaddingTop();
			float x_ratio = (float)mPanoView.getWidth() / (float)mPreviewSize.width;
			float y_ratio = (float)mPanoView.getHeight() / (float)mPreviewSize.height;	
			
			//assume that the activity's requested orientation is same as the lcm orientation.
			//if not,the following caculation would be wrong!!
			if (mDisplayOrientaion == 180){
				if (direction == DIRECTION_LEFT || direction == DIRECTION_RIGHT) {
					direction = 1 - direction;
				} else {
					direction = 5 - direction;
				}
				x = (short)-x;
				y = (short)-y;
			} else if (mDisplayOrientaion == 90) {
				float temp = x_ratio;
				x_ratio = y_ratio;
				y_ratio = -temp;

				int temp2 = cwx;
				cwx = cwy;
				cwy = temp2;
			}
			
            x *= x_ratio;
            y *= y_ratio;
			
            int screenPosX = 0;
            int screenPosY = 0;
            
            switch (direction) {
            case DIRECTION_RIGHT:
            	screenPosX = -x + cwx + (int)(TARGET_DISTANCE_HORIZONTAL * x_ratio);
            	screenPosY = -y + cwy;
            	break;
            case DIRECTION_LEFT:
            	screenPosX = -x + cwx + (int)(-TARGET_DISTANCE_HORIZONTAL * x_ratio);
            	screenPosY = -y + cwy;
            	break;
            case DIRECTION_UP:
            	screenPosX = -x + cwx;
            	screenPosY = -y + cwy + (int)(-TARGET_DISTANCE_VERTICAL * y_ratio);
            	break;
            case DIRECTION_DOWN:
            	screenPosX = -x + cwx;
            	screenPosY = -y + cwy + (int)(TARGET_DISTANCE_VERTICAL * y_ratio);
            	break;
            }
			Xlog.i(TAG, "onFrame x = "+x/x_ratio + " y = "+y/y_ratio + " cwx = "+cwx + " cwy = "+cwy+" screenPosX = "+screenPosX 
				+ " screenPosY = "+screenPosY);

			int w = mNaviWindow.getWidth();
			int h = mNaviWindow.getHeight();
			if (mDisplayOrientaion == 90) {
				if (direction == DIRECTION_LEFT || direction == DIRECTION_RIGHT) {
					direction = 3 - direction;
				} else {
					direction -= 2;
				}
				
				int temp = screenPosX;
				screenPosX = screenPosY;
				screenPosY = temp;

				temp = w;
				w = h;
				h = temp;				
			}			
			
			updateDirection(direction);
			mNaviWindow.setVisibility(View.VISIBLE);
			mNaviWindow.layout(screenPosX,screenPosY,
				screenPosX+w,screenPosY+h);
        }
    	
}

